unit ComplexOps;

{
  PasCalc
  Version 1.2 2011-05-26

  Copyright (C) 2011 KEEPER <yar.keeper@gmail.com>

  This file is part of the PasCalc Calculator

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See the file LICENSE.TXT, included in this distribution,
  for details about the copyright.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}

interface

uses
  SysUtils, Math;

type

  TComplex = record
    re: extended;
    im: extended;
  end;

  TExpComplex = record
    abs: extended;
    arg: extended;
  end;

  PComplex = ^TComplex;

function Plus(const Arg1, Arg2: TComplex): TComplex;
function Minus(const Arg1, Arg2: Tcomplex): TComplex;
function Mult(const Arg1, Arg2: TComplex): TComplex;
function UnMinus(const Arg: TComplex): TComplex;
function Divide(const Arg1, Arg2: TComplex; var DivZero: boolean): TComplex;
function Interf(const Arg: TComplex): TComplex;
function ComplToStr(Compl: TComplex): ShortString; overload;
function ComplToStr(Compl: TComplex; const size, fract: integer): ShortString; overload;
function ComplToStr(Compl: TExpComplex): ShortString; overload;
function ComplToStr(Compl: TExpComplex; const size, fract: integer): ShortString; overload;
function Compl2ExpCompl(Compl: TComplex): TExpComplex;
function ExpCompl2Compl(ExpCompl: TExpComplex): TComplex;
function Factorial(Arg: integer): int64;

var
  IsRad: boolean;

implementation

function ComplToStr(Compl: TComplex): ShortString;
begin
  if abs(Compl.im) < 1e-14 then Compl.im := 0;
  if abs(Compl.re) < 1e-14 then Compl.re := 0;
  result := '';
  if compl.im = 0 then
  begin
    result := FloatToStr(Compl.re);
    exit;
  end;
  if Compl.re <> 0 then result := FloatToStr(Compl.re);
  if Compl.im = 0 then exit;
  if (Compl.im < 0) or (compl.re = 0) then result := result +
    FloatToStr(Compl.im) else
     result := result + '+' + FloatToStr(Compl.im);
  result := result + 'i';
end;

function ComplToStr(Compl: TComplex; const size, fract: integer): ShortString; overload;
begin
  if abs(Compl.im) < 1e-14 then Compl.im := 0;
  if abs(Compl.re) < 1e-14 then Compl.re := 0;
  result := '';
  if compl.im = 0 then
  begin
    result := FloatToStrF(Compl.re, ffgeneral, size, fract);
    exit;
  end;
  if Compl.re <> 0 then result := FloatToStrF(Compl.re, ffgeneral, size, fract);
  if Compl.im = 0 then exit;
  if (Compl.im < 0) or (compl.re = 0) then result := result +
    FloatToStrF(Compl.im, ffgeneral, size, fract) else
     result := result + '+' + FloatToStrF(Compl.im, ffgeneral, size, fract);
  result := result + 'i';
end;

function ComplToStr(Compl: TExpComplex): ShortString; overload;
begin
  result := '';
  if abs(Compl.abs) < 1e-14 then exit;
  result := result + FloatToStr(Compl.abs);
  if abs(Compl.arg) < 1e-14 then exit;
  result := result + 'e' + FloatToStr(Compl.arg) + 'i';
end;

function ComplToStr(Compl: TExpComplex; const size, fract: integer
  ): ShortString; overload;
begin
  result := '';
  if abs(Compl.abs) < 1e-14 then exit;
  result := result + FloatToStrF(Compl.abs, ffGeneral, Size, Fract);
  if abs(Compl.arg) < 1e-14 then exit;
  result := result + 'e' + FloatToStrF(Compl.arg, ffGeneral, Size, Fract) + 'i';
end;

function Compl2ExpCompl(Compl: TComplex): TExpComplex;
begin
  result.abs := sqrt(sqr(Compl.re)+sqr(Compl.im));
  if not IsRad then result.arg := RadToDeg(arccos(Compl.re/result.abs))
    else result.arg := arccos(Compl.im/result.abs)
end;

function ExpCompl2Compl(ExpCompl: TExpComplex): TComplex;
begin
  if IsRad then
  begin
    result.re := ExpCompl.abs*cos(ExpCompl.arg);
    result.im := ExpCompl.abs*sin(ExpCompl.arg);
  end else
  begin
    result.re := ExpCompl.abs*cos(DegToRad(ExpCompl.arg));
    result.im := ExpCompl.abs*sin(DegToRad(ExpCompl.arg));
  end;
end;

function Factorial(Arg: integer): int64;
var
  i: integer;
begin
  result := 1;
  for i := 1 to arg do
  begin
    result := result * i;
  end;
end;

function Plus(const Arg1, Arg2: TComplex): TComplex;
begin
  result.re := Arg1.re + Arg2.re;
  result.im := Arg1.im + Arg2.im;
end;

function Minus(const Arg1, Arg2: Tcomplex): TComplex;
begin
  result.re := Arg1.re - Arg2.re;
  result.im := Arg1.im - Arg2.im;
end;

function Mult(const Arg1, Arg2: TComplex): TComplex;
begin
  result.re := Arg1.re*Arg2.re-Arg1.im*Arg2.im;
  result.im := Arg1.re*Arg2.im+Arg1.im*Arg2.re;
end;

function UnMinus(const Arg: TComplex): TComplex;
begin
  result.re := -Arg.re;
  result.im := -Arg.im;
end;

function Interf(const Arg: TComplex): TComplex;
begin
  result.im := -Arg.im;
  result.re := Arg.re;
end;

function Divide(const Arg1, Arg2: TComplex; var DivZero: boolean): TComplex;
var
  top: TComplex;
  bottom: extended;
begin
  top := Mult(Arg1, Interf(Arg2));
  bottom := Sqr(Arg2.re) + Sqr(Arg2.im);
  if Abs(bottom) < 1e-14 then
  begin
    DivZero := true;
    exit;
  end;
  Result.re := top.re/bottom;
  result.im := top.im/bottom;
end;

initialization
  IsRad := false;

end.
